#include "pch.h"
#include "IOHelper.h"
#include "Factories.h"
#include "Helper.h"
#include <vector>

using namespace Platform;
using namespace DXBase;
using namespace Microsoft::WRL;
using namespace Windows::Foundation;
using namespace Windows::Storage;
using namespace concurrency;

using namespace DXBase;
using namespace std;

static std::vector<StorageFolder^> GetSupportedFolders()
{
	vector<StorageFolder^> supported;
	supported.push_back(Windows::Storage::ApplicationData::Current->LocalFolder);
	supported.push_back(Windows::ApplicationModel::Package::Current->InstalledLocation);
	return supported;
}
static Wrappers::FileHandle OpenFile(String^ filename)
{
    CREATEFILE2_EXTENDED_PARAMETERS extendedParams = {0};
    extendedParams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
    extendedParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
    extendedParams.dwFileFlags = FILE_FLAG_SEQUENTIAL_SCAN;
    extendedParams.dwSecurityQosFlags = SECURITY_ANONYMOUS;
    extendedParams.lpSecurityAttributes = nullptr;
    extendedParams.hTemplateFile = nullptr;

	// open and check it's a supported file
    Wrappers::FileHandle file(CreateFile2(filename->Data(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &extendedParams));
    if (file.Get() == INVALID_HANDLE_VALUE)
		return Wrappers::FileHandle(INVALID_HANDLE_VALUE);

    FILE_STANDARD_INFO fileInfo = {0};
    if (!GetFileInformationByHandleEx(file.Get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))
		return Wrappers::FileHandle(INVALID_HANDLE_VALUE);

	// big file are not supported
    if (fileInfo.EndOfFile.HighPart != 0)
		return Wrappers::FileHandle(INVALID_HANDLE_VALUE);

	return file;
}

bool IOHelper::FileReachable(String^ filename)
{
	auto file = OpenFile(filename);
	return file.Get() != INVALID_HANDLE_VALUE;
}

Platform::String^ IOHelper::FullPath(Platform::String^ filename)
{
	if (FileReachable(filename))
		return filename;

	auto folders = ::GetSupportedFolders();
	for (size_t i = 0; i < folders.size(); i++)
	{
		auto folder = folders[0];
		auto fullpath = folder->Path + "\\" + filename;
		if (FileReachable(fullpath))
			return fullpath;
	}
	return nullptr;
}
Array<byte>^ IOHelper::ReadFile(Platform::String^ filename)
{
	filename = FullPath(filename);
	if (!filename)
		return nullptr;

	auto file = ::OpenFile(filename);
    FILE_STANDARD_INFO info = {0};
    if (!GetFileInformationByHandleEx(file.Get(), FileStandardInfo, &info, sizeof(FILE_STANDARD_INFO)))
        throw ref new Platform::FailureException();
    auto data = ref new Array<byte>(info.EndOfFile.LowPart);
    if (!::ReadFile(file.Get(), data->Data, data->Length, nullptr, nullptr))
        throw ref new Platform::FailureException();
	return data;
}
ComPtr<IStream> IOHelper::Bytes2Stream(const Platform::Array<byte>^ bytes)
{
    ComPtr<IWICStream> stream;
	HR2Ex(Factories::GetWicFactory()->CreateStream(&stream));
	HR2Ex(stream->InitializeFromMemory(bytes->Data, bytes->Length));
	return stream;
}

